;---- ; Example program switching to Protected and back to Real Mode ; Jerzy Tarasiuk 8-Jun-1995 ; code segment assume cs:code stk segment para stack 'stack' dw 100h dup(?) stk ends assume cs:code,ss:stk,ds:Nothing,es:Nothing .386P ;- ; GDT to be used in Protected Mode ; mygdt dq 0 ; null descriptor gdtcd dw -1,0,9A00h,0 ; 64kB code segment, base to be set dw -1,0,9200h,008Fh ; 4GB R/W segment, base=0 dw -1,0,9200h,0 ; 64kB R/W segment, base=0 ;--- ; pm_mem - access memory (peek/poke a byte) in Protected Mode ; ; entry EBX=address, CX=0 for peek to CL or CX!=0 for poke CL ; changes EAX,EDX,GDTR,CL ; ; requires A20 to be enabled if to be used on a PC compatible ; (A20 is usually enabled if DOS is loaded into HMA) ; pm_mem proc pushf push ds mov ax,cs movzx eax,ax shl eax,4 ; eax=base for code segment mov dword ptr gdtcd[2],eax mov byte ptr gdtcd[5],9Ah ; set segment attribute mov dx,offset mygdt movzx edx,dx add eax,edx ; eax=base for GDT push eax push 20h movzx eax,sp cli ; make sure no ISR will interfere now lgdt fword ptr ss:[eax] ; LGDT is necessary before switch to PM add sp,6 mov eax,cr0 or al,1 mov cr0,eax ; sets Protected Mode db 0eah ; far jump to set CS & clear prefetch queue dw pm_in dw 8 pm_in: mov dx,10h mov ds,dx ; load long segment descriptor from GDT into DS jcxz pm_get mov [ebx],cl pm_get: mov cl,[ebx] mov dl,18h mov ds,dx ; load 64kB segment descriptor from GDT into DS and al,not 1 mov cr0,eax ; sets Real Mode db 0eah ; far jump to restore CS & clear prefetch queue dd pm_out ; it MUST be jump - far return crashed! pm_out: pop ds popf ret pm_mem endp ;--- ; vfycpu - make sure have proper CPU, in Real Mode, and A20 enabled ; ; changes AX,DX ; returns AL=error code if anything wrong ; error codes: 040h - not 32-bit CPU (PM,A20 not tested) ; 001h - already in PM (386+, A20 not tested) ; 0FFh - A20 disabled (32-bit CPU in RM) ; vfycpu proc pushf ; save flags cli ; make sure no ISR will interfere now ; pushf ; 1. make sure have at least 386 pop ax ; AX=flags xor ah,40h ; toggle NT push ax ; stack: modified_flags,original_flags popf pushf ; stack: modified_flags_from_cpu,original_flags pop dx ; DX=flags passed via CPU mov al,dh xor al,ah jnz vcfail ; improper CPU ; smsw ax ; 2. make sure are in Real Mode and al,1 jnz vcfail ; if already in PM (maybe VM86) ; push ds ; 3. make sure A20 is enabled push es push bx xor bx,bx mov ds,bx mov ax,-1 mov es,ax xor [bx],ah ; change byte[000000h] mov al,es:[bx+10h] ; get byte[100000h] xor [bx],ah ; change byte[000000h] xor al,es:[bx+10h] ; compare byte[100000h] with its previous value ; 0 if unchanged, -1 means [000000h]==[100000h] pop bx pop es pop ds ; vcfail: popf ; restore flags test al,al ; test error code ret vfycpu endp ;--- ; sample program ; - check if have proper CPU, exit with error message if bad ; - peek byte[0FFFFFFF0h] in PM ; - peek byte[0FFFEFFF0h] in PM ; - exit (status = byte obtatained) ; badcpum db "Not 80386+ CPU!",0Dh,0Ah,'$' inpmerm db "Already in Protected Mode!",0Dh,0Ah,'$' bada20m db "Address line A20 disabled!",0Dh,0Ah,'$' start: call vfycpu ; make sure having proper CPU and mode add al,al jz cpuok ; .. OK lea dx,bada20m jc error lea dx,badcpum js error lea dx,inpmerm error: push cs ; not proper - error message and exit pop ds mov ah,9 int 21h mov ax,4cffh ; exit, status=-1 int 21h cpuok: xor cx,cx ; peek a byte mov ebx,-10h ; from 0FFFFFFF0h call pm_mem xor cx,cx ; peek a byte mov ebx,-10010h ; from 0FFFEFFF0h call pm_mem exit: mov ah,4ch ; exit mov al,cl ; status = the byte int 21h code ends end start